package com.sciencep.pro.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sciencep.pro.common.config.Constant;
import com.sciencep.pro.common.domain.OscaConstant;
import com.sciencep.pro.common.domain.QueryRequest;
import com.sciencep.pro.common.domain.ResponseResult;
import com.sciencep.pro.common.exception.CustomException;
import com.sciencep.pro.common.utils.SortUtil;
import com.sciencep.pro.core.dao.ProBaseInfoMapper;
import com.sciencep.pro.core.dao.ProDataMapper;
import com.sciencep.pro.core.dao.ProPlanHoursMapper;
import com.sciencep.pro.core.dao.UserWorkdailyLogMapper;
import com.sciencep.pro.core.domain.dto.dropdown.ProSelectVO;
import com.sciencep.pro.core.domain.dto.home.ParticipatedInInfoVO;
import com.sciencep.pro.core.domain.dto.prohistory.ProHistoryTo;
import com.sciencep.pro.core.domain.dto.project.*;
import com.sciencep.pro.core.domain.dto.user.UserDetail;
import com.sciencep.pro.core.domain.dto.workdailylog.WorkdailyLogTO;
import com.sciencep.pro.core.domain.entity.*;
import com.sciencep.pro.core.domain.vo.project.ProDateInfo;
import com.sciencep.pro.core.service.*;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Sciencep
 */
@Service
@Slf4j
public class ProBaseInfoServiceImpl extends ServiceImpl<ProBaseInfoMapper, ProBaseInfo> implements IProBaseInfoService {

    @Autowired
    IProTypeService proTypeService;

    @Autowired
    IProContactService contactService;

    @Autowired
    IProDataService proDataService;

    @Autowired
    IProNodeDateService proNodeDateService;

    @Resource
    ProBaseInfoMapper proBaseInfoMapper;

    @Autowired
    IProChangebaseService proChangebaseService;

    @Autowired
    IProChangedetailService proChangedetailService;

    @Autowired
    IProAssignmentService assignmentService;

    @Autowired
    IUserRoleService userRoleService;

    @Autowired
    IDeptService deptService;

    @Autowired
    DingDingService dingDingService;

    @Autowired
    IBranchContactService branchContactService;

    @Resource
    ProPlanHoursMapper proPlanHoursMapper;

    @Resource
    UserWorkdailyLogMapper workdailyLogMapper;

    @Resource
    ProDataMapper proDataMapper;

    @Autowired
    IBranchService branchService;

    @Autowired
    IProChangeHoursService proChangeHoursService;

    @Autowired
    ICalendarInfoService calendarInfoService;

    @Autowired
    IProPlanHoursService proPlanHoursService;

    @Autowired
    IRoleService roleService;


    @Autowired
    IProNodeService proNodeService;

    @Autowired
    ITokenInfoService tokenInfoService;

    @Autowired
    IUserWorkdailyLogBackService userWorkdailyLogBackService;

    @Autowired
    @Lazy
    IUserWorkdailyLogService userWorkdailyLogService;

    @Autowired
    IUserService userService;

    @Autowired
    IProAssignmentService proAssignmentService;

    @Autowired
    IUserDeptService userDeptService;

    @Autowired
    IProHistoryService proHistoryService;

    String yMd = "yyyy-MM-dd";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult<Object> saveProject(ProjectTO projectTO, UserDetail userDetail) throws CustomException {


        ProType proType = proTypeService.getById(projectTO.getProTypeId());
        if (proType == null) {
            throw new CustomException("类型不存在");
        }

        if (this.getOne(new LambdaQueryWrapper<ProBaseInfo>().eq(ProBaseInfo::getProCode, projectTO.getProCode())) != null) {
            ProBaseInfo proBaseInfo = new ProBaseInfo();
            proBaseInfo.setProTypeId(projectTO.getProTypeId().toString());
            ProjectTO projectTO1 = this.getProjectCode(proBaseInfo);
            return new ResponseResult<>().failure("1002", "存在相同的项目编号,已为您更改,请再次提交", projectTO1.getProCode());
        }

        ProBaseInfo proBaseInfo = new ProBaseInfo();
        proBaseInfo.setProTypeId(String.valueOf(projectTO.getProTypeId()));
        proBaseInfo.setProNodeId(projectTO.getProNodeId());
        proBaseInfo.setProCode(projectTO.getProCode());
        proBaseInfo.setProName(projectTO.getProName());
        proBaseInfo.setProPriority(projectTO.getProPriority());
        if (projectTO.getBranchIds() != null && projectTO.getBranchIds().length > 0) {
            proBaseInfo.setBranchId(StringUtils.join(projectTO.getBranchIds(), ","));
        }

        proBaseInfo.setProSummary(projectTO.getProSummary());
        proBaseInfo.setProNotice(projectTO.getProNotice());
        proBaseInfo.setProStartDay(projectTO.getProStartDay());
        proBaseInfo.setProEndday(projectTO.getProEndday());
        proBaseInfo.setProManager(projectTO.getProManager());
        proBaseInfo.setContractCode(projectTO.getContractCode());
        proBaseInfo.setDeptId(projectTO.getDeptId());

        //基础信息
        proBaseInfo.setIsDel(Constant.IsDelete.NO);
        proBaseInfo.setCreateDate(new Date());
        proBaseInfo.setCreateUserId(userDetail.getUserId());
        proBaseInfo.setCreateUserName(userDetail.getUserName());
        proBaseInfo.setProStatus(1);

        this.save(proBaseInfo);
        Long proId = proBaseInfo.getId();
        if (CollUtil.isNotEmpty(projectTO.getBranchContactIds())) {
            // 批量储存联系人
            List<ProContact> proContactList = new ArrayList<>();
            projectTO.getBranchContactIds().forEach(o -> {
                ProContact proContact = new ProContact();
                proContact.setProId(proId).setContactId(o);
                proContact.setIsDel(Constant.IsDelete.NO);
                proContactList.add(proContact);

            });

            contactService.saveBatch(proContactList);
        }
        if (CollUtil.isNotEmpty(projectTO.getProData())) {
            // 项目资料
            List<ProData> proDataList = new ArrayList<>();
            projectTO.getProData().forEach(o -> {
                ProData proData = new ProData();
                proData.setProId(proId);
                proData.setProNodeId(o.getProNodeId());
                proData.setProDataId(o.getProDataId());
                proData.setMustFlag(o.getMustFlag());
                proData.setGitAdr(o.getGitAdr());
                proData.setIsDel(Constant.IsDelete.NO);
                proData.setCreateUserId(userDetail.getUserId());
                proData.setCreateUserName(userDetail.getUserName());
                proDataList.add(proData);
            });
            proDataService.saveBatch(proDataList);
        }

        if (CollUtil.isNotEmpty(projectTO.getProNodeDate())) {
            // 项目分派
            List<ProNodeDate> proNodeDateList = new ArrayList<>();
            projectTO.getProNodeDate().forEach(o -> {

                ProNodeDate proNodeDate = new ProNodeDate();
                proNodeDate.setEndDate(o.getEndDate()).setStartDate(o.getStartDate()).setProId(proId);
                proNodeDate.setIsDel(Constant.IsDelete.NO);
                proNodeDate.setProNodeId(o.getProNodeId());
                proNodeDateList.add(proNodeDate);
            });
            proNodeDateService.saveBatch(proNodeDateList);
        }


        return new ResponseResult<>().success(proBaseInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProject(ProjectTO projectTO, UserDetail userDetail) throws CustomException {
        ProType proType = proTypeService.getById(projectTO.getProTypeId());
        if (proType == null) {
            throw new CustomException("类型不存在");
        }
        ProBaseInfo proBaseInfo1 = this.getById(projectTO.getId());
        if (null == proBaseInfo1) {
            throw new CustomException("项目不存在");

        }

        ProBaseInfo proBaseInfo = new ProBaseInfo();

        proBaseInfo.setId(projectTO.getId());
        proBaseInfo.setProTypeId(String.valueOf(projectTO.getProTypeId()));
        proBaseInfo.setProNodeId(projectTO.getProNodeId());
        proBaseInfo.setContractCode(projectTO.getContractCode());
        proBaseInfo.setProName(projectTO.getProName());
        proBaseInfo.setProPriority(projectTO.getProPriority());
        if (projectTO.getBranchIds() != null && projectTO.getBranchIds().length > 0) {
            proBaseInfo.setBranchId(StringUtils.join(projectTO.getBranchIds(), ","));
        }
        proBaseInfo.setProSummary(projectTO.getProSummary());
        proBaseInfo.setProNotice(projectTO.getProNotice());
        proBaseInfo.setProStartDay(projectTO.getProStartDay());
        proBaseInfo.setProEndday(projectTO.getProEndday());
        proBaseInfo.setProManager(projectTO.getProManager());
        proBaseInfo.setDeptId(projectTO.getDeptId());
        //基础信息
        proBaseInfo.setIsDel(Constant.IsDelete.NO);
        proBaseInfo.setModifyDate(new Date());
        proBaseInfo.setModifyUserId(userDetail.getUserId());
        proBaseInfo.setModifyUserName(userDetail.getUserName());


        this.updateById(proBaseInfo);
        Long proId = proBaseInfo.getId();

        contactService.remove(new LambdaQueryWrapper<ProContact>().eq(ProContact::getProId, proId));
        if (CollUtil.isNotEmpty(projectTO.getBranchContactIds())) {
            // 批量储存联系人
            List<ProContact> proContactList = new ArrayList<>();
            projectTO.getBranchContactIds().forEach(o -> {
                ProContact proContact = new ProContact();
                proContact.setProId(proId).setContactId(o);
                proContact.setIsDel(Constant.IsDelete.NO);
                proContactList.add(proContact);

            });

            contactService.saveBatch(proContactList);
        }
        proDataService.remove(new LambdaQueryWrapper<ProData>().eq(ProData::getProId, proId));
        if (CollUtil.isNotEmpty(projectTO.getProData())) {
            // 项目资料
            List<ProData> proDataList = new ArrayList<>();
            projectTO.getProData().forEach(o -> {
                ProData proData = new ProData();
                proData.setProId(proId);
                proData.setProNodeId(o.getProNodeId());
                proData.setProDataId(o.getProDataId());
                proData.setMustFlag(o.getMustFlag());
                proData.setGitAdr(o.getGitAdr());
                proData.setIsDel(Constant.IsDelete.NO);
                proData.setCreateUserId(userDetail.getUserId());
                proData.setCreateUserName(userDetail.getUserName());
                proData.setModifyUserId(userDetail.getUserId());
                proData.setModifyUserName(userDetail.getUserName());
                proData.setModifyDate(new Date());
                proDataList.add(proData);
            });
            proDataService.saveBatch(proDataList);
        }

        proNodeDateService.remove(new LambdaQueryWrapper<ProNodeDate>().eq(ProNodeDate::getProId, proId));
        if (CollUtil.isNotEmpty(projectTO.getProNodeDate())) {
            // 项目分派
            List<ProNodeDate> proNodeDateList = new ArrayList<>();
            projectTO.getProNodeDate().forEach(o -> {

                ProNodeDate proNodeDate = new ProNodeDate();
                proNodeDate.setEndDate(o.getEndDate()).setStartDate(o.getStartDate()).setProId(proId)
                        .setProNodeId(o.getProNodeId());
                proNodeDate.setIsDel(Constant.IsDelete.NO);
                proNodeDateList.add(proNodeDate);
            });
            proNodeDateService.saveBatch(proNodeDateList);
        }

    }

    @Override
    public ProjectTO editProjectInit(ProBaseInfo proBaseInfo) throws ParseException {
        ProjectTO projectTO = proBaseInfoMapper.editProjectInit(proBaseInfo);
        if (StringUtils.isNotBlank(projectTO.getBranchId())) {
            projectTO.setBranchIds(projectTO.getBranchId().split(","));
        }

        if (projectTO.getProEndday().compareTo(projectTO.getProStartDay()) > 0) {
            projectTO.setWorkDate(this.getWork(projectTO));
        }
        if (CollUtil.isNotEmpty(projectTO.getProNodeList())) {
            for (ProNodeTO proNodeTO : projectTO.getProNodeList()) {

                proNodeTO.setProDateInfoList(this.getWork(proNodeTO));

                SimpleDateFormat sdf = new SimpleDateFormat(yMd);
                Date startDate = sdf.parse(proNodeTO.getStartDate());
                Date endDate = sdf.parse(proNodeTO.getEndDate());

                Date currentDate = sdf.parse(sdf.format(new Date()));

                if (startDate.compareTo(currentDate) <= 0 && endDate.compareTo(currentDate) >= 0) {
                    proNodeTO.setCurrent(true);
                }
            }
        }
        return projectTO;
    }

    @Override
    public ProjectTO getProjectInfo(ProBaseInfo proBaseInfo) throws ParseException {
        ProjectTO projectTO = null;
        try {
            projectTO = this.editProjectInit(proBaseInfo);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        //20210125 新需求(历史数据统计)
        ProHistoryTo proHistoryTo = proHistoryService.getProgress(proBaseInfoMapper.selectOne(new LambdaQueryWrapper<ProBaseInfo>().eq(ProBaseInfo::getId, proBaseInfo.getId())).getProCode());

        //设置服务器当前时间
        projectTO.setServerDate(new SimpleDateFormat(yMd).format(Calendar.getInstance().getTime()));

        projectTO.setProjectSumPlanDay(proBaseInfoMapper.getProjectSumPlanDay(proBaseInfo).getProjectSumPlanDay() == null ? "0" : proBaseInfoMapper.getProjectSumPlanDay(proBaseInfo).getProjectSumPlanDay());
        //20210125 新需求(历史数据统计)
        if(proHistoryTo != null && proHistoryTo.getSumPlanInputHours() != null && !"".equals(proHistoryTo.getSumPlanInputHours())){
            projectTO.setProjectSumPlanDay(new BigDecimal(projectTO.getProjectSumPlanDay()).add(new BigDecimal(proHistoryTo.getSumPlanInputHours())).toString());
        }
        projectTO.setProjectSumRealityDay(proBaseInfoMapper.getProjectSumRealityDay(proBaseInfo).getProjectSumRealityDay() == null ? "0" : proBaseInfoMapper.getProjectSumRealityDay(proBaseInfo).getProjectSumRealityDay());
        //20210125 新需求(历史数据统计)
        if(proHistoryTo != null && proHistoryTo.getSumRealInputHours() != null &&  !"".equals(proHistoryTo.getSumRealInputHours())){
            projectTO.setProjectSumRealityDay(new BigDecimal(projectTO.getProjectSumRealityDay()).add(new BigDecimal(proHistoryTo.getSumRealInputHours())).toString());
        }

        if (null != proBaseInfoMapper.getProgressByCode(projectTO)) {
            projectTO.setProgress(proBaseInfoMapper.getProgressByCode(projectTO));
        }
        //20210125 新需求(历史数据统计)
        if(proHistoryTo != null && proHistoryTo.getProgress() != null &&  null != proHistoryTo.getProgress()){
            ProHistoryTo to = proHistoryService.countProgress(proHistoryTo.getProCode());
            if(null != to){
                projectTO.setProgress(to.getProgress());
            }
        }

        //截至当天之前的计划人天
        String currentProjectSumPlanDay = "";
        if (proBaseInfoMapper.getCurrentSumPlanDay(proBaseInfo) != null) {
            if (proBaseInfoMapper.getCurrentSumPlanDay(proBaseInfo).getProjectSumPlanDay() != null) {
                currentProjectSumPlanDay = proBaseInfoMapper.getCurrentSumPlanDay(proBaseInfo).getProjectSumPlanDay();
            } else {
                currentProjectSumPlanDay = "0";
            }
        }
        //截至当天之前的绩效人天
        String currentSumPerformanceDaily = "";
        if (proBaseInfoMapper.getCurrentSumPerformanceDaily(proBaseInfo) != null) {
            if (proBaseInfoMapper.getCurrentSumPerformanceDaily(proBaseInfo).getProjectSumRealityDay() != null) {
                currentSumPerformanceDaily = proBaseInfoMapper.getCurrentSumPerformanceDaily(proBaseInfo).getProjectSumRealityDay();
            } else {
                currentSumPerformanceDaily = "0";
            }
        }

        //截至当天(包含当天)的绩效人天
        projectTO.setCurrentSumPerformanceDaily(proBaseInfoMapper.getSumPerformanceDaily(proBaseInfo) == null ? "0" : proBaseInfoMapper.getSumPerformanceDaily(proBaseInfo));
        //20210125 新需求(历史数据统计)
        if(proHistoryTo != null && proHistoryTo.getSumRealPerformanceHours() != null &&  !"".equals(proHistoryTo.getSumRealPerformanceHours())){
            projectTO.setCurrentSumPerformanceDaily(new BigDecimal(projectTO.getCurrentSumPerformanceDaily()).add(new BigDecimal(proHistoryTo.getSumRealPerformanceHours())).toString());
        }

        projectTO.setProAssignmentList(proBaseInfoMapper.getProAssignmentList(proBaseInfo));
        //今天之前实际人天,绩效人天为空的置零
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yMd);
        for (ProAssignmentTO proAssignmentTO : projectTO.getProAssignmentList()) {
            for (ProPlanHoursTO proPlanHoursTO : proAssignmentTO.getPlanHoursList()) {
                if (simpleDateFormat.parse(proPlanHoursTO.getPlanDate()).compareTo(simpleDateFormat.parse(simpleDateFormat.format(new Date()))) <= 0) {
                    proPlanHoursTO.setPersonSumPlanDay(proPlanHoursTO.getPersonSumPlanDay() == null ? "0.00" : proPlanHoursTO.getPersonSumPlanDay());
                    proPlanHoursTO.setPersonSumReality(proPlanHoursTO.getPersonSumReality() == null ? "0.00" : proPlanHoursTO.getPersonSumReality());
                }
            }
        }
        double scheduleDay = 0;
        projectTO.setProjectSchedule("暂无进度");//防止没有计划人天
        if (StringUtils.isNotBlank(currentSumPerformanceDaily) && StringUtils.isNotBlank(currentProjectSumPlanDay)) {
            //20210125 新需求(历史数据统计)
            if(proHistoryTo != null && proHistoryTo.getSumRealPerformanceHours() != null && proHistoryTo.getSumPlanInputHours() != null && !"".equals(proHistoryTo.getSumRealPerformanceHours()) && !"".equals(proHistoryTo.getSumPlanInputHours())) {
                currentSumPerformanceDaily = new BigDecimal(currentSumPerformanceDaily).add(new BigDecimal(proHistoryTo.getSumRealPerformanceHours())).toString();
                currentProjectSumPlanDay = new BigDecimal(currentProjectSumPlanDay).add(new BigDecimal(proHistoryTo.getSumPlanInputHours())).toString();
            }

            scheduleDay = Double.parseDouble(currentSumPerformanceDaily) / Double.parseDouble(currentProjectSumPlanDay) - 1;
            projectTO.setProjectSchedule(checkSchedule(scheduleDay));
        }
        List<ProChangebase> changebaseList = proChangebaseService.list(
                new LambdaQueryWrapper<ProChangebase>().eq(ProChangebase::getProId, proBaseInfo.getId())
                        .eq(ProChangebase::getChangeStatus, Constant.ProChangeStatus.START));
        projectTO.setProChangebaseList(changebaseList);
        return projectTO;

    }

    @Override
    public ProjectTO getDelayedProject(ProBaseInfo proBaseInfo) {
        ProjectTO projectTO = new ProjectTO();
        //截至当天之前的计划人天
        String currentProjectSumPlanDay = "";

        // 优化后
        ProjectTO currentSumPlanDay = proBaseInfoMapper.getCurrentSumPlanDay(proBaseInfo);
        if (currentSumPlanDay != null) {
            if (currentSumPlanDay.getProjectSumPlanDay() != null) {
                currentProjectSumPlanDay = currentSumPlanDay.getProjectSumPlanDay();
            } else {
                currentProjectSumPlanDay = "0";
            }
        }

         /*// 优化前
        if (proBaseInfoMapper.getCurrentSumPlanDay(proBaseInfo) != null) {
            if (proBaseInfoMapper.getCurrentSumPlanDay(proBaseInfo).getProjectSumPlanDay() != null) {
                currentProjectSumPlanDay = proBaseInfoMapper.getCurrentSumPlanDay(proBaseInfo).getProjectSumPlanDay();
            } else {
                currentProjectSumPlanDay = "0";
            }
        }*/


        // 截至当天之前的绩效人天
        String currentSumPerformanceDaily = "";
        // 优化后
        ProjectTO currentSumPerformanceDailyObject = proBaseInfoMapper.getCurrentSumPerformanceDaily(proBaseInfo);
        if (currentSumPerformanceDailyObject != null) {
            if (currentSumPerformanceDailyObject.getProjectSumRealityDay() != null) {
                currentSumPerformanceDaily = currentSumPerformanceDailyObject.getProjectSumRealityDay();
            } else {
                currentSumPerformanceDaily = "0";
            }
        }

         /*// 优化前
        if (proBaseInfoMapper.getCurrentSumPerformanceDaily(proBaseInfo) != null) {
            if (proBaseInfoMapper.getCurrentSumPerformanceDaily(proBaseInfo).getProjectSumRealityDay() != null) {
                currentSumPerformanceDaily = proBaseInfoMapper.getCurrentSumPerformanceDaily(proBaseInfo).getProjectSumRealityDay();
            } else {
                currentSumPerformanceDaily = "0";
            }
        }*/
        double scheduleDay = 0;
        projectTO.setProjectSchedule("暂无进度");//防止没有计划人天
        if (StringUtils.isNotBlank(currentSumPerformanceDaily) && StringUtils.isNotBlank(currentProjectSumPlanDay)) {
            scheduleDay = Double.parseDouble(currentSumPerformanceDaily) / Double.parseDouble(currentProjectSumPlanDay) - 1;
            projectTO.setProjectSchedule(checkSchedule(scheduleDay));
        }
        return projectTO;
    }


    /*  实际除以计划
        偏差
        5%以内：如期正常
        5%<偏差<=20%：超前，反之延期
        20%<偏差：大幅超前，反之严重延期*/
    public String checkSchedule(double scheduleDay) {
        String schedule = null;
        if (Constant.Schedule.NORMAL > scheduleDay && scheduleDay >= Constant.Schedule.LOSE_NORMAL) {
            schedule = "如期正常";
        } else if (Constant.Schedule.NORMAL < scheduleDay && scheduleDay <= Constant.Schedule.DELAY) {
            schedule = "项目超前";
        } else if (Constant.Schedule.LOSE_NORMAL > scheduleDay && scheduleDay >= Constant.Schedule.LOSE_DELAY) {
            schedule = "项目延期";
        } else if (Constant.Schedule.DELAY < scheduleDay) {
            schedule = "大幅超前";
        } else if (Constant.Schedule.LOSE_DELAY > scheduleDay) {
            schedule = "严重延期";
        } else {
            schedule = "暂无进度";
        }
        return schedule;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String changeProject(ProjectChangeTO changeTO, UserDetail userDetail) throws CustomException {

        Integer count = proChangebaseService.count(
                new LambdaQueryWrapper<ProChangebase>().eq(ProChangebase::getProId, changeTO.getProId())
                        .eq(ProChangebase::getChangeStatus, Constant.ProChangeStatus.START));
        if (count > 0) {
            throw new CustomException("该项目变更正在审批中，请勿重复提交");
        }
        log.info(JSON.toJSONString(changeTO));
        //生成唯一编号
        String changeNo = UUID.randomUUID().toString();
        ProChangebase proChangebase = new ProChangebase();
        BeanUtils.copyProperties(changeTO, proChangebase);
        proChangebase.setChangeNo(changeNo);
        proChangebase.setProId(changeTO.getProId());
        proChangebase.setCreateDate(new Date());
        proChangebase.setCreateUserName(userDetail.getUserName());
        proChangebase.setCreateUserId(userDetail.getUserId());
        proChangebase.setInputHourNew(changeTO.getInputHourNew());
        proChangebase.setInputHourOld(changeTO.getInputHourOld());


        // 设置变更状态

        proChangebaseService.save(proChangebase);
        Long baseId = proChangebase.getId();
        List<ProChangedetail> proChangedetailList = new ArrayList<>();
        List<ProChangeHours> proChangeHoursList = new ArrayList<>();
        for (AddUserTO addUserTO : changeTO.getAddUserTOList()) {

            proChangeHoursList.addAll(addUserTO.getProChangeHours());
            ProChangedetail proChangedetail = new ProChangedetail();
            proChangedetail.setField1(addUserTO.getUserId());
            proChangedetail.setField2(addUserTO.getUserName());
            proChangedetail.setField3(addUserTO.getInputDaily().toString());
            proChangedetail.setField4(addUserTO.getInputStart());
            proChangedetail.setField5(addUserTO.getInputEnd());
            proChangedetail.setField6(addUserTO.getInputType().toString());
            proChangedetail.setField7(addUserTO.getInputTypeName());
            proChangedetail.setField8(addUserTO.getProRoleId());
            proChangedetail.setChangeType(2);
            proChangedetail.setChangeBaseId(baseId);
            proChangedetail.setIsDel(Constant.IsDelete.NO);
            proChangedetail.setCreateDate(new Date());
            proChangedetail.setCreateUserName(userDetail.getUserName());
            proChangedetail.setCreateUserId(userDetail.getUserId());
            proChangedetailList.add(proChangedetail);
        }
        for (UpdateUserTO updateUserTO : changeTO.getUpdateUserTOList()) {
            ProChangedetail proChangedetail = new ProChangedetail();
            proChangedetail.setField1(updateUserTO.getUserId());
            proChangedetail.setField2(updateUserTO.getUserName());
            proChangedetail.setField3(updateUserTO.getInputTypeNew());
            proChangedetail.setField4(updateUserTO.getInputTypeNameNew());
            proChangedetail.setField5(updateUserTO.getInputDailyNew());
            proChangedetail.setField6(updateUserTO.getInputStartOld());
            proChangedetail.setField7(updateUserTO.getInputEndOld());
            proChangedetail.setField8(updateUserTO.getInputStartNew());
            proChangedetail.setField9(updateUserTO.getInputEndNew());
            proChangedetail.setField10(updateUserTO.getInputTypeOld());
            proChangedetail.setField11(updateUserTO.getInputDailyOld());
            proChangedetail.setField12(updateUserTO.getInputTypeNameOld());
            proChangedetail.setField13(updateUserTO.getProroleId());

            proChangedetail.setChangeType(3);
            proChangedetail.setChangeBaseId(baseId);
            proChangedetail.setIsDel(Constant.IsDelete.NO);
            proChangedetail.setCreateDate(new Date());
            proChangedetail.setCreateUserName(userDetail.getUserName());
            proChangedetail.setCreateUserId(userDetail.getUserId());
            proChangedetailList.add(proChangedetail);
            proChangeHoursList.addAll(updateUserTO.getProChangeHours());
        }
        for (ProChangeHours proChangeHours : proChangeHoursList) {
            proChangeHours.setChangeNo(changeNo).setProId(Long.valueOf(proChangebase.getProId()))
                    .setNodeId(proChangebase.getProNodeId());
        }
        proChangeHoursService.saveBatch(proChangeHoursList);
        proChangedetailService.saveBatch(proChangedetailList);
        return changeNo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditChange(ProChangeAuditTO proChangeAuditTO, UserDetail userDetail) throws CustomException {


        ProChangebase proChangebase = proChangebaseService.getOne(new LambdaQueryWrapper<ProChangebase>().eq(ProChangebase::getChangeNo, proChangeAuditTO.getChangeNo()));
        proChangebase.setChangeStatus(proChangeAuditTO.getChangeStatus()).setApproOpinions(proChangeAuditTO.getApproOpinions());
        proChangebase.setModifyDate(new Date());
        proChangebaseService.updateById(proChangebase);
        // 拒绝
        if (proChangeAuditTO.getChangeStatus().equals(Constant.ReviewStatus.NO)) {
            return;
        }
        //同意
        //修改项目基本信息
        List<ProNodeDate> proNodeDateList = proNodeDateService.
                list(new LambdaQueryWrapper<ProNodeDate>().eq(ProNodeDate::getProId, proChangebase.getProId()).eq(ProNodeDate::getProNodeId, proChangebase.getProNodeId()));
        ProBaseInfo proBaseInfo = this.getById(proChangebase.getProId());
        proBaseInfo.setProEndday(proChangebase.getNewProEndDate());
        proBaseInfo.setProStartDay(proChangebase.getNewProStartDate());
        this.updateById(proBaseInfo);
        //修改节点开始结束日期
        ProNodeDate proNodeDate;
        if (proNodeDateList.size() != 1) {
            throw new CustomException("当前数据有误");
        }
        proNodeDate = proNodeDateList.get(0);
        proNodeDate.setStartDate(proChangebase.getNewNodeStartDate());
        proNodeDate.setEndDate(proChangebase.getNewNodeEndDate());
        proNodeDateService.update(proNodeDate, new LambdaQueryWrapper<ProNodeDate>().eq(ProNodeDate::getProId, proNodeDate.getProId()).eq(ProNodeDate::getProNodeId, proNodeDate.getProNodeId()));
        List<ProChangedetail> proChangedetailList = proChangedetailService.list(new LambdaQueryWrapper<ProChangedetail>().eq(ProChangedetail::getChangeBaseId, proChangebase.getId()));

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(yMd);
        if (CollUtil.isNotEmpty(proChangedetailList)) {
            // 对每一个变化修改数据库
            for (ProChangedetail proChangedetail : proChangedetailList) {
                String userId;
                Date startDate;
                Date endDate;
                Integer inputType;
                String proroleId;
                Float inputHours;
                switch (proChangedetail.getChangeType()) {
                    // 周期变更
                    case 1:
                        break;
                    // 新增人员
                    case 2:
                        try {
                            userId = proChangedetail.getField1();
                            startDate = simpleDateFormat.parse(proChangedetail.getField4());
                            endDate = simpleDateFormat.parse(proChangedetail.getField5());
                            inputType = Integer.valueOf(proChangedetail.getField6());
                            proroleId = proChangedetail.getField8();
                            inputHours = Float.valueOf(proChangedetail.getField3());
                        } catch (Exception e) {
                            e.printStackTrace();
                            throw new CustomException("字段错误");
                        }
                        ProAssignment proAssignment2 = new ProAssignment();
                        proAssignment2.setProId(proBaseInfo.getId());
                        proAssignment2.setNodeId(proNodeDate.getProNodeId());
                        proAssignment2.setNodeStart(proNodeDate.getStartDate());
                        proAssignment2.setNodeEnd(proNodeDate.getEndDate());
                        proAssignment2.setUserId(userId);
                        proAssignment2.setInputType(inputType);
                        proAssignment2.setInputStart(startDate);
                        proAssignment2.setInputEnd(endDate);
                        if (proroleId != null) {
                            proAssignment2.setProroleId(Long.valueOf(proroleId));
                        }
                        proAssignment2.setInputHours(inputHours);

                        //设置默认的评审id和name
                        proAssignment2.setReviewId(proBaseInfo.getProManager());
                        proAssignment2.setReviewName(userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUserId,proBaseInfo.getProManager())).getUserName());

                        assignmentService.remove(new QueryWrapper<ProAssignment>().eq("proId", proAssignment2.getProId())
                                .eq("nodeId", proAssignment2.getNodeId()).eq("userId", proAssignment2.getUserId()));
                        assignmentService.save(proAssignment2);
                        break;
                    // 人员变更
                    case 3:
                        try {
                            userId = proChangedetail.getField1();
                            startDate = simpleDateFormat.parse(proChangedetail.getField8());
                            endDate = simpleDateFormat.parse(proChangedetail.getField9());
                            inputType = Integer.valueOf(proChangedetail.getField3());
                            proroleId = proChangedetail.getField13();
                            inputHours = Float.valueOf(proChangedetail.getField5());
                        } catch (Exception e) {
                            throw new CustomException("字段错误");
                        }
                        ProAssignment proAssignment = assignmentService.getOne(
                                new LambdaQueryWrapper<ProAssignment>().
                                        eq(ProAssignment::getUserId, userId).
                                        eq(ProAssignment::getProId, proBaseInfo.getId()).
                                        eq(ProAssignment::getNodeId, proNodeDate.getProNodeId()));
                        proAssignment.setProId(proBaseInfo.getId());
                        proAssignment.setNodeId(proNodeDate.getProNodeId());
                        proAssignment.setNodeStart(proNodeDate.getStartDate());
                        proAssignment.setNodeEnd(proNodeDate.getEndDate());
                        proAssignment.setUserId(userId);
                        proAssignment.setInputType(inputType);
                        proAssignment.setInputStart(startDate);
                        proAssignment.setInputEnd(endDate);
                        proAssignment.setReadType(0);
                        if (proroleId != null) {
                            proAssignment.setProroleId(Long.valueOf(proroleId));
                        }
                        proAssignment.setInputHours(inputHours);
                        assignmentService.updateById(proAssignment);
                        break;
                    default:
                        break;
                }
            }
        }
        //修改人天
        List<ProChangeHours> proChangeHoursList = proChangeHoursService
                .list(new LambdaQueryWrapper<ProChangeHours>().eq(ProChangeHours::getChangeNo, proChangebase.getChangeNo()));
        if (CollUtil.isNotEmpty(proChangeHoursList)) {
            List<ProPlanHours> proPlanHoursList = new ArrayList<>();
            Set<String> keySet = new HashSet<>();
            for (ProChangeHours proChangeHours : proChangeHoursList) {
                String key = proChangeHours.getProId() + "-" + proChangeHours.getNodeId() + "-" + proChangeHours.getUserId();
                keySet.add(key);
                ProPlanHours proPlanHours = new ProPlanHours();
                proPlanHours.setUserId(proChangeHours.getUserId()).setProId(proChangeHours.getProId())
                        .setNodeId(proChangeHours.getNodeId()).setPlanDate(proPlanHours.getPlanDate())
                        .setInputHours(proChangeHours.getInputHours()).setIsDel(Constant.IsDelete.NO);
                proPlanHours.setPlanDate(proChangeHours.getChangeDate());
                proPlanHoursList.add(proPlanHours);
            }
            for (String key : keySet) {
                String[] keys = key.split("-");
                proPlanHoursService.remove(new LambdaQueryWrapper<ProPlanHours>()
                        .eq(ProPlanHours::getNodeId, keys[1]).eq(ProPlanHours::getProId, keys[0])
                        .eq(ProPlanHours::getUserId, keys[2]));
            }
            proPlanHoursService.saveBatch(proPlanHoursList);


        }
    }

    @Override
    public ProjectTO getProjectCode(ProBaseInfo proBaseInfo) {
        ProType proType = proTypeService.getById(proBaseInfo.getProTypeId());
        // 输入参数+系统年月日+随机3位数字
        //生成以后查询 项目基本信息表，如果没有重复的就采用该编号，如果有重复的，随机3位数字重新生成，
        //重复上述过程直到没有重复的项目编号
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");//设置日期格式
        String date = simpleDateFormat.format(new Date());
        int random = (int) ((Math.random() * 900) + 100);
        if (proType != null) {
            ProjectTO projectTO = new ProjectTO();
            String proCode = proType.getTypeCode() + date + random;
            while (proTypeService.getOne(new LambdaQueryWrapper<ProType>().eq(ProType::getTypeCode, proCode)) != null) {
                proCode = proType.getTypeCode() + date + random;
            }
            projectTO.setProCode(proCode);
            return projectTO;
        } else {
            return null;
        }
    }

    @Override
    public List<ProSelectVO> getInprocessingProList(String userId) {

        List<ProSelectVO> result = new ArrayList<>();
        // 项目表probaseinfo中查找项目负责人ID为当前登录人的所有项目
        //result.addAll(baseMapper.getProjectsByUserIdWithPm(userId));

        //人天分配表中指定的日志评审人
        List<ProAssignment> proAssignmentList = proAssignmentService.list(new LambdaQueryWrapper<ProAssignment>().
                groupBy(ProAssignment::getProId,ProAssignment::getUserId).
                eq(ProAssignment::getReviewId, userId));
        Set<Long> proAssignmentNo = proAssignmentList.stream().map(ProAssignment::getProId).collect(Collectors.toSet());

        List<ProSelectVO> proAssignmentNos = new ArrayList<>();
        proAssignmentNo.forEach(e->{
            ProSelectVO proSelectVO = new ProSelectVO();
            proSelectVO.setProNo(baseMapper.selectOne(new LambdaQueryWrapper<ProBaseInfo>().eq(ProBaseInfo::getId,e)).getProCode());
            proSelectVO.setProName(baseMapper.selectOne(new LambdaQueryWrapper<ProBaseInfo>().eq(ProBaseInfo::getId,e)).getProName());
            proAssignmentNos.add(proSelectVO);
        });

        //查询所有所属部门所有子部门
        Set<String> deptSet = deptService.
                list(new LambdaQueryWrapper<Dept>().like(Dept::getDeptManagerUseridList, userId))
                .stream().map(Dept::getDeptId).collect(Collectors.toSet());

        //递归查询部门下所有部门
        Set<String> allFollowDeptSet = new HashSet<>();
        if(!CollectionUtils.isEmpty(deptSet)){
            allFollowDeptSet.addAll(deptSet);
            for(String tempDept : deptSet){
                queryfollowdeptSet(allFollowDeptSet,tempDept);
            }
        }

        //找到项目主管下的所有人
        Set<String> userSet = new HashSet<>();
        allFollowDeptSet.forEach(e -> {
            userDeptService.list(new LambdaQueryWrapper<UserDept>().eq(UserDept::getDeptId,e)).forEach(d->{
                userSet.add(d.getUserId());
            });
        });

        if (CollUtil.isNotEmpty(userSet)) {
            userWorkdailyLogService.list(new LambdaQueryWrapper<UserWorkdailyLog>()
                    .select(UserWorkdailyLog::getProNo,UserWorkdailyLog::getProName)
                    .in(UserWorkdailyLog::getUserId, userSet)
                    .ne(UserWorkdailyLog::getProNo,"OTHER0001"))
                    .stream().forEach(o ->
                    result.add(new ProSelectVO().setProName(o.getProName()).setProNo(o.getProNo()))
            );
        }
        result.addAll(proAssignmentNos);
        List<ProSelectVO> fresult = result.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(()
                -> new TreeSet<>(Comparator.comparing(ProSelectVO::getProNo))), ArrayList::new));
        fresult.add(new ProSelectVO().setProName("其它项目").setProNo(Constant.OTHER0001));
        return fresult;
    }

    private void queryfollowdeptSet(Set<String> deptSet, String tempDept) {
        Set<String> tempSet = deptService.list(new LambdaQueryWrapper<Dept>().like(Dept::getParentId, tempDept))
                .stream().map(Dept::getDeptId).collect(Collectors.toSet());
        if(!CollectionUtils.isEmpty(tempSet)){
            for(String temp : tempSet){
                deptSet.add(temp);
                queryfollowdeptSet(deptSet,temp);
            }
        }
        return;
    }

    @Override
    public List<ProSelectVO> getAll() {


        List<ProBaseInfo> proBaseInfos = this.list();
        List<ProSelectVO> result = new ArrayList<>();
        for (ProBaseInfo proBaseInfo : proBaseInfos) {
            result.add(new ProSelectVO().setProName(proBaseInfo.getProName()).setProNo(proBaseInfo.getProCode()));
        }
        result.add(new ProSelectVO().setProName("其它项目").setProNo(Constant.OTHER0001));
        return result;
    }

    @Override
    public List<ProSelectVO> getProAndBakList() {
        //项目表
        List<ProBaseInfo> proBaseInfos = this.list();
        List<ProSelectVO> result = new ArrayList<>();
        for (ProBaseInfo proBaseInfo : proBaseInfos) {
            result.add(new ProSelectVO().setProName(proBaseInfo.getProName()).setProNo(proBaseInfo.getProCode()));
        }
        //日志备份表
        List<UserWorkdailyLogBack> userWorkdailyLogBackList = userWorkdailyLogBackService.list().stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(UserWorkdailyLogBack::getProNo))), ArrayList::new));
        for (UserWorkdailyLogBack userWorkdailyLogBack : userWorkdailyLogBackList) {
            if (!userWorkdailyLogBack.getProNo().equals(Constant.OTHER0001)) {
                result.add(new ProSelectVO().setProName(userWorkdailyLogBack.getProName()).setProNo(userWorkdailyLogBack.getProNo()));
            }
        }
        result.add(new ProSelectVO().setProName("其它项目").setProNo(Constant.OTHER0001));
        return result;
    }

    @Override
    public List<MandayStatisticsChartTO> getMandayStatisticsChart(String proId, String proNo, Integer type) {


        List<PeopleWorkDayTO> totalWorkList;
        List<PeopleWorkDayTO> finshWorkDayList;
        List<PeopleWorkDayTO> performanceDailyDay;

        if (type.equals(1)) {
            totalWorkList = baseMapper.getAssignmentDay(proId);
            finshWorkDayList = baseMapper.getFinishDay(proNo);
            performanceDailyDay = baseMapper.getPerformanceDailyDay(proNo);
        } else if (type.equals(2)) {
            totalWorkList = baseMapper.getAssignmentDayRole(proId);
            finshWorkDayList = baseMapper.getFinishDayRole(proNo);
            performanceDailyDay = baseMapper.getPerformanceDailyDayRole(proNo);
        } else {
            return new ArrayList<>();
        }
        Map<String, PeopleWorkDayTO> totalMap = totalWorkList.stream().collect(Collectors.toMap(PeopleWorkDayTO::getUserId, peopleWorkDayTO -> peopleWorkDayTO));
        Map<String, PeopleWorkDayTO> finishMap = finshWorkDayList.stream().collect(Collectors.toMap(PeopleWorkDayTO::getUserId, peopleWorkDayTO -> peopleWorkDayTO));
        Map<String, PeopleWorkDayTO> performanceMap = performanceDailyDay.stream().collect(Collectors.toMap(PeopleWorkDayTO::getUserId, peopleWorkDayTO -> peopleWorkDayTO));
        Set<String> nameSet = new HashSet<>();
        nameSet.addAll(totalMap.keySet());
        nameSet.addAll(finishMap.keySet());
        nameSet.addAll(performanceMap.keySet());
        if (nameSet.isEmpty()) {
            return new ArrayList<>();
        }
        List<MandayStatisticsChartTO> result = new ArrayList<>();
        for (String s : nameSet) {
            MandayStatisticsChartTO mandayStatisticsChartTO = new MandayStatisticsChartTO();
            PeopleWorkDayTO total = totalMap.get(s);
            if (total != null) {
                mandayStatisticsChartTO.setTotal(total.getDay());
                mandayStatisticsChartTO.setText(total.getName());
            }
            PeopleWorkDayTO finsh = finishMap.get(s);
            if (finsh != null) {
                mandayStatisticsChartTO.setDone(finsh.getDay());
                mandayStatisticsChartTO.setText(finsh.getName());
            }
            PeopleWorkDayTO per = performanceMap.get(s);
            if (per != null) {
                mandayStatisticsChartTO.setRealDone(per.getDay());
                mandayStatisticsChartTO.setText(per.getName());
            }
            if (mandayStatisticsChartTO.getTotal() != null && mandayStatisticsChartTO.getDone() != null) {
                mandayStatisticsChartTO.setLast(mandayStatisticsChartTO.getTotal() - mandayStatisticsChartTO.getDone());
            }
            result.add(mandayStatisticsChartTO);
        }
        return result;

    }

    @Override
    public List<BurndownChartTO> getBurndownChartTO(String proId, String proNo) {

        ProBaseInfo proBaseInfo = this.getById(proId);
        if (proBaseInfo == null) {
            return new ArrayList<>();
        }
        //得出项目起止日期
        LocalDate startDate = proBaseInfo.getProStartDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        LocalDate endDate = proBaseInfo.getProEndday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        //得出计划总人天
        List<ProAssignment> assignments =
                assignmentService.list(new QueryWrapper<ProAssignment>().eq("proId", proId));
        Float totalHours = 0f;
        for (ProAssignment proAssignment : assignments) {
            totalHours += proAssignment.getInputHours();
        }
        List<BurndownChartTO> dateHourLeftTOList = proPlanHoursMapper.getTotalWorkDay(proId);
        float sum = 0f;
        for (BurndownChartTO burndownChartTO : dateHourLeftTOList) {
            sum += burndownChartTO.getTotalPlan();
            log.info(sum + "");
            if (totalHours - sum >= 0) {
                burndownChartTO.setTotalPlan((float) (Math.round((totalHours - sum) * 100)) / 100);
            } else {
                burndownChartTO.setTotalPlan(0);
            }

        }
        List<BurndownChartTO> realLeftDays = workdailyLogMapper.getRealLeftWorkDay(proNo);
        float sum2 = 0f;
        for (BurndownChartTO burndownChartTO : realLeftDays) {
            sum2 += burndownChartTO.getTotalReal();
            if (totalHours - sum2 >= 0) {
                burndownChartTO.setTotalReal((float) (Math.round((totalHours - sum2) * 100)) / 100);
            } else {
                burndownChartTO.setTotalReal(0);
            }
        }

        List<BurndownChartTO> result = new ArrayList<>();
        float suma = 0;
        float sumb = 0;
        while (startDate.compareTo(endDate) <= 0) {
            BurndownChartTO burndownChartTO = new BurndownChartTO();
            burndownChartTO.setDate(startDate);
            for (BurndownChartTO burndownChartTO2 : dateHourLeftTOList) {
                if (startDate.equals(burndownChartTO2.getDate())) {
                    suma = burndownChartTO2.getTotalPlan();
                    burndownChartTO.setTotalPlan(burndownChartTO2.getTotalPlan());
                }
            }
            for (BurndownChartTO burndownChartTO3 : realLeftDays) {
                if (startDate.equals(burndownChartTO3.getDate())) {
                    sumb = burndownChartTO3.getTotalReal();
                    burndownChartTO.setTotalReal(burndownChartTO3.getTotalReal());
                }
            }
            burndownChartTO.setTotalPlan(suma);
            burndownChartTO.setTotalReal(sumb);
            result.add(burndownChartTO);
            startDate = startDate.plusDays(1);
        }
        return result;
    }

    @Override
    public List<WorkloadTrendChartTO> getWorkloadTrendChartTOList(String proId, String proNo) {

        ProBaseInfo proBaseInfo = this.getById(proId);
        if (proBaseInfo == null) {
            return new ArrayList<>();
        }
        LocalDate startDate = proBaseInfo.getProStartDay().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        LocalDate endDate = proBaseInfo.getProEndday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        List<UserWorkdailyLog> userWorkdailyLogList = proPlanHoursMapper.getPutinDaily(proNo, startDate, endDate);

        List<WorkloadTrendChartTO> result = new ArrayList<>();

        while (startDate.compareTo(endDate) <= 0) {
            WorkloadTrendChartTO item = new WorkloadTrendChartTO();
            item.setDate(startDate);
            if (CollUtil.isNotEmpty(userWorkdailyLogList)) {
                for (UserWorkdailyLog userWorkdailyLog : userWorkdailyLogList) {
                    if (startDate.toString().equals(new SimpleDateFormat(yMd).format(userWorkdailyLog.getWorkDate()))) {
                        item.setDate(userWorkdailyLog.getWorkDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
                        item.setTotalInputHours(userWorkdailyLog.getPerformanceDaily().floatValue());
                        result.add(item);
                    }
                }
            }
            result.add(item);
            startDate = startDate.plusDays(1);
        }


        return result;
    }

    @Override
    public Integer getDelayCount() {
        return baseMapper.getDelayCount();
    }

    @Override
    public ProChangeDetailTO getProChangeDetailTO(String proId, String proNodeId) {

        ProChangebase proChangebase = proChangebaseService.getOne(
                new LambdaQueryWrapper<ProChangebase>().eq(ProChangebase::getProId, proId)
                        .eq(ProChangebase::getChangeStatus, Constant.ProChangeStatus.START).eq(ProChangebase::getProNodeId, proNodeId));

        if (proChangebase == null) {
            return new ProChangeDetailTO();
        }
        ProChangeDetailTO proChangeDetailTO = new ProChangeDetailTO();
        proChangeDetailTO.setProNodeCount(assignmentService.count(new LambdaQueryWrapper<ProAssignment>().eq(ProAssignment::getProId, proId)));
        proChangeDetailTO.setOldProStartDate(proChangebase.getOldProStartDate());
        proChangeDetailTO.setOldProEndDate(proChangebase.getOldProEndDate());
        proChangeDetailTO.setNewProStartDate(proChangebase.getNewProStartDate());
        proChangeDetailTO.setNewProEndDate(proChangebase.getNewProEndDate());
        proChangeDetailTO.setChangeSummary(proChangebase.getChangeSummary());

        proChangeDetailTO.setOldNodeStartDate(proChangebase.getOldNodeStartDate());
        proChangeDetailTO.setOldNodeEndDate(proChangebase.getOldNodeEndDate());
        proChangeDetailTO.setNewNodeStartDate(proChangebase.getNewNodeStartDate());
        proChangeDetailTO.setNewNodeEndDate(proChangebase.getNewNodeEndDate());
        try {
            proChangeDetailTO.setProName(proBaseInfoMapper.selectById(proId).getProName());
            proChangeDetailTO.setNodeName(proNodeService.getById(proChangebase.getProNodeId()).getNodeName());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        proChangeDetailTO.setProPutinOld(proChangebase.getInputHourOld());
        proChangeDetailTO.setProPutinNew(proChangebase.getInputHourNew());
        proChangeDetailTO.setChangeNo(proChangebase.getChangeNo());
        List<AddUserTO> addUserTOList = new ArrayList<>();
        List<UpdateUserTO> updateUserTOList = new ArrayList<>();
        List<ProChangedetail> proChangedetailList = proChangedetailService.list(new LambdaQueryWrapper<ProChangedetail>().
                eq(ProChangedetail::getChangeBaseId, proChangebase.getId()));
        for (ProChangedetail detail : proChangedetailList) {
            if (detail.getChangeType().equals(2)) {
                AddUserTO addUserTO = new AddUserTO();
                addUserTO.setInputDaily(Double.valueOf(detail.getField3()));
                addUserTO.setUserId(detail.getField1());
                addUserTO.setUserName(detail.getField2());
                addUserTO.setInputStart(detail.getField4());
                addUserTO.setInputEnd(detail.getField5());
                addUserTO.setInputType(Integer.valueOf(detail.getField6()));
                addUserTO.setInputTypeName(detail.getField7());
                try {
                    addUserTO.setInputDaily(Double.valueOf(detail.getField3()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
                addUserTOList.add(addUserTO);
            }
            if (detail.getChangeType().equals(3)) {
                UpdateUserTO updateUserTO = new UpdateUserTO();
                updateUserTO.setUserId(detail.getField1());
                updateUserTO.setUserName(detail.getField2());
                updateUserTO.setInputTypeNew(detail.getField3());
                updateUserTO.setInputTypeNameOld(detail.getField12());
                updateUserTO.setInputTypeNameNew(detail.getField4());
                updateUserTO.setInputDailyNew(detail.getField5());
                updateUserTO.setInputDailyOld(detail.getField11());
                updateUserTOList.add(updateUserTO);
            }
            proChangeDetailTO.setAddUserTOList(addUserTOList);
            proChangeDetailTO.setUpdateUserTOList(updateUserTOList);
        }

        return proChangeDetailTO;
    }

    @Override
    public List<ProDataTO> getProjectInfoData(String proId) {


        return proDataMapper.getProjectInfoData(proId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveToDingDing(ProjectTO projectTO, UserDetail userDetail) throws CustomException, ApiException {
        if (null != projectTO.getId()) {
            this.updateProject(projectTO, userDetail);
        }
        ProBaseInfo proBaseInfo = this.getOne(new LambdaQueryWrapper<ProBaseInfo>().eq(ProBaseInfo::getProCode, projectTO.getProCode()));
        if (proBaseInfo == null) {
            throw new CustomException("项目不存在");
        }
        if (proBaseInfo.getProStatus() == null) {
            throw new CustomException("项目异常");
        }

        if (!proBaseInfo.getProStatus().equals(1)) {
            throw new CustomException("项目已经提交审批");
        }
        // branchId是 "[1,2,3]" 先转成list
        if (StringUtils.isNotBlank(proBaseInfo.getBranchId())) {
            List<String> branchIds = new ArrayList<>(Arrays.asList(proBaseInfo.getBranchId().split(",")));
            List<Branch> branchList = branchService.listByIds(branchIds);
            if (CollUtil.isNotEmpty(branchList)) {
                // 得到项目名字排列
                proBaseInfo.setBranchName(branchList.stream().map(Branch::getDataName).collect(Collectors.joining(",")));
            } else {
                proBaseInfo.setBranchName(" ");
            }
            List<BranchContact> branchContactList = branchContactService.getContactByProId(proBaseInfo.getId().toString(), proBaseInfo.getBranchId());
            if (CollUtil.isNotEmpty(branchContactList)) {
                // 得到联系人名字排列
                String contactName = branchContactList.stream().map(BranchContact::getContactName).collect(Collectors.joining(","));
                proBaseInfo.setContactName(contactName);
            } else {
                proBaseInfo.setContactName("  ");
            }

        } else {
            proBaseInfo.setBranchName(" ");
        }
        // 提交到钉钉审核
        TokenInfo tokenInfo = tokenInfoService.getOne(new LambdaQueryWrapper<TokenInfo>().eq(TokenInfo::getIsDel, Constant.IsDelete.NO).eq(TokenInfo::getType, 1));
        dingDingService.createProcessInstance(proBaseInfo, dingDingService.getAccessToken(tokenInfo.getAppKey(), tokenInfo.getAppSecret()),
                userDetail.getUserId());


    }

    @Override
    public ProBaseInfo finishProject(ProBaseInfo proBaseInfo) {
        proBaseInfo.setProStatus(Constant.ProStatus.FINISH);
        proBaseInfoMapper.updateById(proBaseInfo);
        return proBaseInfo;
    }

    @Override
    public ProBaseInfo updateContractCode(ProBaseInfo proBaseInfo) {
        proBaseInfoMapper.updateById(proBaseInfo);
        return proBaseInfo;
    }

    @Override
    public Page<ParticipatedInInfoVO> getMyProject(String userId, QueryRequest queryRequest) {
        Page<ParticipatedInInfoVO> page = new Page<>();
        SortUtil.handlePageSort(queryRequest, page, "proId", OscaConstant.ORDER_DESC, false);
        Page<ParticipatedInInfoVO> myProject = proBaseInfoMapper.getMyProject(userId, page);

        myProject.getRecords().forEach(e->{
            //20210125 新需求(历史数据统计)
            ProHistoryTo proHistoryTo = proHistoryService.getProgress(e.getProCode());
            if(proHistoryTo != null && !"".equals(proHistoryTo.getProCode()) && !"".equals(proHistoryTo.getProgress())) {
                if (e.getProCode().equals(proHistoryTo.getProCode())) {
                    ProHistoryTo to = proHistoryService.countProgress(proHistoryTo.getProCode());
                    if(null != to){
                        e.setProgress(to.getProgress());
                    }
                }
            }
        });
        return myProject;
    }

    public static Set<String> getSubDeptList(Set<String> deptSet, List<Dept> deptList) {
        boolean flag = false;
        do {
            flag = false;
            for (Dept dept : deptList) {
                if (deptSet.contains(dept.getParentId()) && (!deptSet.contains(dept.getDeptId()))) {
                    deptSet.add(dept.getDeptId());
                    flag = true;
                }
            }
        } while (flag);
        return deptSet;
    }


    @Override
    public List<Map<String, Boolean>> getWorkDay(String beginDate, String endDate) {
        List<Map<String, Boolean>> list = new ArrayList<>();
        List<CalendarInfo> calendarInfoList = calendarInfoService.list(new LambdaQueryWrapper<CalendarInfo>().between(CalendarInfo::getDate, beginDate, endDate).orderByAsc(CalendarInfo::getDate));
        SimpleDateFormat sdf = new SimpleDateFormat(yMd);
        if (CollUtil.isNotEmpty(calendarInfoList)) {
            for (CalendarInfo calendarInfo : calendarInfoList) {
                Map<String, Boolean> map = new HashMap<>();
                //自定义的工作日字段为空就使用第三方的工作日
                if (null != calendarInfo.getCustomHoliday()) {
                    map.put(sdf.format(calendarInfo.getDate()), calendarInfo.getCustomHoliday() == 1);
                } else {
                    map.put(sdf.format(calendarInfo.getDate()), calendarInfo.getWorkDay() == 1);
                }
                list.add(map);
            }
        }
        return list;
    }

    /**
     * 获取一段时间的工作日和非工作日
     *
     * @param proNodeTO
     * @return
     */
    public List<ProDateInfo> getWork(ProNodeTO proNodeTO) {
        List<ProDateInfo> proDateInfoList = new ArrayList<>();
        List<CalendarInfo> calendarInfoList = calendarInfoService.list(new LambdaQueryWrapper<CalendarInfo>().between(CalendarInfo::getDate, proNodeTO.getStartDate(), proNodeTO.getEndDate()).orderByAsc(CalendarInfo::getDate));
        SimpleDateFormat sdf = new SimpleDateFormat(yMd);
        if (CollUtil.isNotEmpty(calendarInfoList)) {
            for (CalendarInfo calendarInfo : calendarInfoList) {
                ProDateInfo proDateInfo = new ProDateInfo();
                proDateInfo.setWorkDate(sdf.format(calendarInfo.getDate()));
                //自定义的工作日字段为空就使用第三方的工作日
                if (null != calendarInfo.getCustomHoliday()) {
                    proDateInfo.setWork(calendarInfo.getCustomHoliday() == 1);
                } else {
                    proDateInfo.setWork(calendarInfo.getWorkDay() == 1);

                }
                proDateInfoList.add(proDateInfo);
            }
        }
        return proDateInfoList;

    }

    /**
     * 获取一段时间的工作日和非工作日
     *
     * @param projectTO
     * @return
     */
    public Integer getWork(ProjectTO projectTO) {
        Date startDate = projectTO.getProStartDay();
        Date endDate = projectTO.getProEndday();
        Integer date = 0;
        List<CalendarInfo> calendarInfoList = calendarInfoService.list(new LambdaQueryWrapper<CalendarInfo>().between(CalendarInfo::getDate, startDate, endDate).orderByAsc(CalendarInfo::getDate));
        if (CollUtil.isNotEmpty(calendarInfoList)) {
            for (CalendarInfo calendarInfo : calendarInfoList) {
                //自定义的工作日字段为空就使用第三方的工作日
                if (null != calendarInfo.getCustomHoliday()) {
                    if (calendarInfo.getCustomHoliday() == 1) {
                        date += 1;
                    }
                } else {
                    if (calendarInfo.getWorkDay() == 1) {
                        date += 1;
                    }
                }
            }
        }
        return date;
    }


}
